package com.rentcars.security;

import com.rentcars.entity.Resource;
import com.rentcars.mapper.ResourceMapper;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 类描述：SHIRO 配置
 *
 * @author 张吉哲
 * @date 2021/3/2 11:23
 */
@Configuration
public class ShireConfiguration {

  /**
   * 日志
   */
  private Logger logger = LoggerFactory.getLogger(ShireConfiguration.class);

  @Bean("shiroRealmImpl")
  public ShiroRealmImpl getShiroRealm() {
    //实例化 ShiroRealmImpl 类，返回一个ShiroRealmImpl 对象。
    return new ShiroRealmImpl();
  }

  @Bean("shiroEhCacheManager")
  public EhCacheManager getEhCacheManager() {
    EhCacheManager ehCacheManager = new EhCacheManager();
    //读取配置文件信息
    ehCacheManager.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml");
    return ehCacheManager;
  }

  @Bean("lifecycleBeanPostProcessor")
  public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
    return new LifecycleBeanPostProcessor();
  }

  @Bean
  public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
    DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
    defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
    return defaultAdvisorAutoProxyCreator;
  }

  @Bean(name = "securityManager")
  public DefaultWebSecurityManager getDefaultWebSecurityManager() {
    DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
    defaultWebSecurityManager.setRealm(getShiroRealm());
    defaultWebSecurityManager.setCacheManager(getEhCacheManager());
    return defaultWebSecurityManager;
  }

  @Bean
  public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {
    AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
    authorizationAttributeSourceAdvisor.setSecurityManager(getDefaultWebSecurityManager());
    return authorizationAttributeSourceAdvisor;
  }

  private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean,
      ResourceMapper resourceMapper) {
    //定义一个 map 集合 存放 权限的URL 地址。
    Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(16);

    //获取所有系统权限资源信息。从数据看获取所有的权限资源信息。
    List<Resource> resources = resourceMapper.selectAllResources(0);
    //遍历从数据查询到的所有  权限资源信息。
    for (Resource resource : resources) {
      //将对应资源权限的地址和名字加入map集合，key 是 权限资源的URL，
      // value 是：authc,perms["+resource.getPermisname()+"]
      filterChainDefinitionMap
          .put(resource.getRelateurl(), "authc,perms[" + resource.getPermisname() + "]");
      //写入日志信息。
      logger.info("##################系统权限【" + resource.getPermisname() + "】##################");
    }
    //在map 集合中插入 初始页面：/home  和备注。
    filterChainDefinitionMap.put("/home", "authc");
    filterChainDefinitionMap.put("/**", "anon");

    //将map 集合传递到 shiroFilterFactoryBean shiro 工厂。
    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
  }

  @Bean("shiroFilterFactoryBean")
  public ShiroFilterFactoryBean getShiroFilterFactoryBean(
      DefaultWebSecurityManager defaultWebSecurityManager, ResourceMapper resourceMapper) {
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    // 必须设置 SecurityManager
    shiroFilterFactoryBean.setSecurityManager(getDefaultWebSecurityManager());
    // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
    shiroFilterFactoryBean.setLoginUrl("/");
    // 登录成功后要跳转的连接
    shiroFilterFactoryBean.setSuccessUrl("/home");
    // 权限校验失败后要跳转的连接
    shiroFilterFactoryBean.setUnauthorizedUrl("/403");
    //调用上面的方法 load 加载shiroFilter权限控制规则（从数据库读取然后配置）
    loadShiroFilterChain(shiroFilterFactoryBean, resourceMapper);
    //返回 shiro 过滤工厂集合。
    return shiroFilterFactoryBean;
  }
}
